package leetcode; /**
 * description:
 * author:zt
 * date:2021-08-31
 */

/**
 * 存在一个不含 0 的 环形 数组nums ，每个 nums[i] 都表示位于下标 i 的角色应该向前或向后移动的下标个数：
 *
 * 如果 nums[i] 是正数，向前（下标递增方向）移动 |nums[i]| 步
 * 如果nums[i] 是负数，向后（下标递减方向）移动 |nums[i]| 步
 * 因为数组是 环形 的，所以可以假设从最后一个元素向前移动一步会到达第一个元素，而第一个元素向后移动一步会到达最后一个元素。
 *
 * 数组中的 循环 由长度为 k 的下标序列 seq 标识：
 *
 * 遵循上述移动规则将导致一组重复下标序列 seq[0] -> seq[1] -> ... -> seq[k - 1] -> seq[0] -> ...
 * 所有 nums[seq[j]] 应当不是 全正 就是 全负
 * k > 1
 * 如果 nums 中存在循环，返回 true ；否则，返回 false 。
 */
//快慢指针判断是否有环
public class leetcode457 {
    int[] nums;
    int n;
    public boolean circularArrayLoop(int[] nums) {
        this.n = nums.length;
        this.nums = nums;

        // 按照题意，起点seq[0]可能不从下标0开始
        for(int i = 0; i < n; ++i){
            int slow = i, fast = next(i);
            // 检查同向
            while(nums[fast] * nums[slow] > 0 && nums[next(fast)] * nums[slow] > 0){
                if(fast == slow){
                    if(slow == next(slow)) break; // 存在长度k为1的同向环
                    else return true; // 否则满足要求
                }
                // 指针移动
                fast = next(next(fast));
                slow = next(slow);
            }
        }

        return false;
    }

    private int next(int i){
        // 注意java下标不能像python有负数，-1需要处理成n-1
        return ((i + nums[i]) % n + n) % n;
    }
}
